package com.zenithmind.disk.config;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;

import com.zenithmind.common.config.AuthInterceptorConfig;

import lombok.extern.slf4j.Slf4j;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * 网盘服务安全配置
 * 遵循单一职责原则：专注于安全配置管理
 * 遵循开闭原则：通过配置类和枚举便于扩展
 * 遵循依赖倒置原则：依赖抽象配置而非具体实现
 */
@Slf4j
@Configuration
@EnableWebSecurity
public class DiskServiceSecurityConfig {

    /**
     * 端点类型枚举
     * 遵循开闭原则：新增端点类型时只需添加枚举值
     */
    public enum EndpointType {
        /** API文档端点 */
        API_DOCS,
        /** 公开访问端点 */
        PUBLIC,
        /** 用户权限端点 */
        USER,
        /** 管理员权限端点 */
        ADMIN
    }

    /**
     * 安全端点配置管理器
     * 遵循单一职责原则：专门管理端点配置
     */
    public static class SecurityEndpointManager {

        // OpenAPI endpoints
        private static final String[] AUTH_WHITELIST = {
            // SpringDoc OpenAPI endpoints
            "/v3/api-docs/**",
            "/swagger-ui/**",
            "/swagger-ui.html",
            "/doc.html",
            "/webjars/**",
            // Knife4j endpoints
            "/favicon.ico",
            "/knife4j/**",
            "/knife4j-ui/**",
            "/knife4j.html"
        };

        /**
         * 公开端点配置 - 统一管理认证拦截器和Spring Security的跳过路径
         * 开发者可以在这里统一配置所有需要跳过认证的端点
         */
        private static final String[] PUBLIC_ENDPOINTS = {
            // 文件公开分享端点 - 允许游客访问公开分享的文件
            "/api/zenithMind/share/getPublicShare",
            "/api/zenithMind/files/downloadFile",
            "/api/zenithMind/files/downloadFolder",
            // 健康检查和其他公开端点
            "/actuator/**",
            "/health",
            "/info"
        };

        // 需要用户角色的端点
        private static final String[] USER_ENDPOINTS = {
            "/api/zenithMind/files/**",
            "/api/zenithMind/share/**",
            "/api/zenithMind/recycleBin/**"
        };

        // 需要管理员角色的端点
        private static final String[] ADMIN_ENDPOINTS = {
            "/api/zenithMind/files/deleteBatchFiles",
            "/api/zenithMind/files/addOrUpdateFile",
            "/api/zenithMind/recycleBin/deleteBatchRecycleBin",
            "/api/zenithMind/recycleBin/addOrUpdateRecycleBin"
        };

        /**
         * 获取指定类型的端点配置
         * @param type 端点类型
         * @return 端点路径数组
         */
        public static String[] getEndpoints(EndpointType type) {
            switch (type) {
                case API_DOCS:
                    return AUTH_WHITELIST.clone();
                case PUBLIC:
                    return PUBLIC_ENDPOINTS.clone();
                case USER:
                    return USER_ENDPOINTS.clone();
                case ADMIN:
                    return ADMIN_ENDPOINTS.clone();
                default:
                    return new String[0];
            }
        }

        /**
         * 获取公开端点列表（用于认证拦截器配置）
         * @return 公开端点列表
         */
        public static List<String> getPublicEndpointsList() {
            return Collections.unmodifiableList(Arrays.asList(PUBLIC_ENDPOINTS));
        }

        /**
         * 检查端点是否为公开端点
         * @param path 端点路径
         * @return true如果是公开端点
         */
        public static boolean isPublicEndpoint(String path) {
            if (path == null || path.trim().isEmpty()) {
                return false;
            }

            for (String endpoint : PUBLIC_ENDPOINTS) {
                if (pathMatches(path, endpoint)) {
                    return true;
                }
            }
            return false;
        }

        /**
         * 检查路径是否匹配模式
         * @param path 实际路径
         * @param pattern 匹配模式
         * @return true如果匹配
         */
        private static boolean pathMatches(String path, String pattern) {
            if (pattern.endsWith("/**")) {
                String prefix = pattern.substring(0, pattern.length() - 3);
                return path.startsWith(prefix);
            } else if (pattern.endsWith("/*")) {
                String prefix = pattern.substring(0, pattern.length() - 2);
                return path.startsWith(prefix) && !path.substring(prefix.length()).contains("/");
            } else {
                return path.equals(pattern);
            }
        }

        /**
         * 获取端点配置统计信息
         * @return 配置统计信息
         */
        public static String getConfigurationSummary() {
            return String.format(
                "安全端点配置统计 - API文档端点: %d, 公开端点: %d, 用户端点: %d, 管理员端点: %d",
                AUTH_WHITELIST.length,
                PUBLIC_ENDPOINTS.length,
                USER_ENDPOINTS.length,
                ADMIN_ENDPOINTS.length
            );
        }
    }

    /**
     * 网盘服务安全配置
     * 遵循单一职责原则：专注于安全过滤链配置
     */
    @Bean
    @Order(1)
    public SecurityFilterChain diskSecurityFilterChain(HttpSecurity http) throws Exception {

        log.info("正在配置网盘服务安全过滤链");
        log.info(SecurityEndpointManager.getConfigurationSummary());

        http
            // 禁用CSRF保护
            .csrf(AbstractHttpConfigurer::disable)
            // 配置认证和授权规则
            .authorizeHttpRequests(authorize -> {
                // 明确允许API文档相关端点
                authorize.requestMatchers(SecurityEndpointManager.getEndpoints(EndpointType.API_DOCS)).permitAll();
                // 允许公开端点 - 使用统一配置
                authorize.requestMatchers(SecurityEndpointManager.getEndpoints(EndpointType.PUBLIC)).permitAll();
                // 用户角色端点
                authorize.requestMatchers(SecurityEndpointManager.getEndpoints(EndpointType.USER)).authenticated();
                // 管理员角色端点
                authorize.requestMatchers(SecurityEndpointManager.getEndpoints(EndpointType.ADMIN)).hasRole("ADMIN");
                // 其他请求需要认证
                authorize.anyRequest().authenticated();
            })
            // 使用无状态会话
            .sessionManagement(session -> session
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            // 禁用OAuth2资源服务器功能
            .oauth2ResourceServer(AbstractHttpConfigurer::disable);

        log.info("网盘服务安全过滤链配置完成");
        return http.build();
    }

    /**
     * 配置认证拦截器的跳过路径
     * 使用统一的端点配置，确保Spring Security和认证拦截器使用相同的跳过路径
     * 遵循依赖倒置原则：通过BeanPostProcessor解耦配置依赖
     */
    @Bean
    public BeanPostProcessor diskAuthPropertiesPostProcessor() {
        return new AuthPropertiesPostProcessor();
    }

    /**
     * 认证属性后处理器
     * 遵循单一职责原则：专门负责认证属性的配置
     */
    private static class AuthPropertiesPostProcessor implements BeanPostProcessor {

        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            if (bean instanceof AuthInterceptorConfig.AuthProperties && "authProperties".equals(beanName)) {
                AuthInterceptorConfig.AuthProperties properties = (AuthInterceptorConfig.AuthProperties) bean;
                List<String> publicEndpoints = SecurityEndpointManager.getPublicEndpointsList();
                properties.setSkipPaths(publicEndpoints);
                log.info("已为网盘服务认证拦截器设置统一的跳过路径配置，路径数量: {}", publicEndpoints.size());
                log.debug("跳过路径详情: {}", publicEndpoints);
            }
            return bean;
        }
    }

    /**
     * 获取安全端点管理器实例
     * 提供给其他组件使用的工厂方法
     * @return 安全端点管理器
     */
    public static SecurityEndpointManager getSecurityEndpointManager() {
        return new SecurityEndpointManager();
    }
}